package com.ms.base.jdbc.dao;

import com.ms.base.comm.db.DbType;
import com.ms.base.comm.util.FrameUtil;
import com.ms.base.page.core.IPage;
import com.ms.base.page.core.PageModel;
import com.ms.base.page.core.PageUtil;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <b>description</b>： <br>
 * <b>time</b>：2018-07-26 16:56 <br>
 * <b>author</b>： ready likun_557@163.com
 */
public abstract class BaseDaoImpl<K, T> implements IBaseDao<K, T> {

    @Override
    public T insert(T model) {
        this.getBaseMapper().insert(model);
        return model;
    }

    @Override
    public void insertBatch(List<T> modelList) {
        if (modelList != null && !modelList.isEmpty()) {
            this.getBaseMapper().insertBatch(modelList);
        }
    }

    @Override
    public int update(T model) {
        return this.getBaseMapper().update(model);
    }

    @Override
    public int updateByMap(Map<String, Object> map) {
        return this.getBaseMapper().updateByMap(map);
    }

    @Override
    public int delete(Map<String, Object> map) {
        return this.getBaseMapper().delete(map);
    }

    @Override
    public int deleteById(Object id) {
        if (id == null) {
            throw new NullPointerException("id is not null!");
        }
        Map map = new HashMap();
        map.put(this.getPrimaryKeyName(), id);
        return this.delete(map);
    }

    @Override
    public long getModelListCount(Map<String, Object> map) {
        return this.getBaseMapper().getModelListCount(map);
    }

    @Override
    public List<T> getModelList(Map<String, Object> map) {
        return this.getBaseMapper().getModelList(map);
    }

    @Override
    public long getModelListCount(String sqlMapId, Map<String, Object> map) throws Exception {
        if (StringUtils.isEmpty(sqlMapId)) {
            return this.getModelListCount(map);
        } else {
            Method method = ReflectionUtils.findMethod(this.getBaseMapper().getClass(), sqlMapId, Map.class);
            return (Long) ReflectionUtils.invokeMethod(method, this.getBaseMapper(), map);
        }
    }

    @Override
    public List getModelList(String sqlMapId, Map<String, Object> map) throws Exception {
        if (StringUtils.isEmpty(sqlMapId)) {
            return this.getModelList(map);
        } else {
            Method method = ReflectionUtils.findMethod(this.getBaseMapper().getClass(), sqlMapId, Map.class);
            return (List) ReflectionUtils.invokeMethod(method, this.getBaseMapper(), map);
        }
    }

    @Override
    public T getModelById(K id) {
        if (id == null) {
            throw new NullPointerException("id is not null!");
        }
        Map<String, Object> map = new HashMap();
        map.put(this.getPrimaryKeyName(), id);
        return this.getModelOne(map);
    }

    @Override
    public List<T> getModelsByIds(List idList) {
        if (idList == null || idList.isEmpty()) {
            return new ArrayList<T>();
        }
        Map map = new HashMap();
        map.put(SQL_IDLIST_KEY, idList);
        return this.getModelList(map);
    }

    @Override
    public Map<K, T> getModelMapByIds(List<K> idList) throws Exception {
        Map map = new HashMap();
        if (idList != null && idList.size() >= 1) {
            List list = this.getModelsByIds(idList);
            if (list != null) {
                for (Object model : list) {
                    Field field = model.getClass().getDeclaredField(this.getPrimaryKeyName());
                    if (!field.isAccessible()) {
                        field.setAccessible(true);
                    }
                    map.put(field.get(model), model);
                }
            }
        }
        return map;
    }

    @Override
    public T getModelOne(Map<String, Object> paramMap) {
        if (paramMap == null) {
            paramMap = new HashMap();
        }
        if (!paramMap.containsKey(PageUtil.ROWSTARTINDEX_KEY)) {
            paramMap.put(PageUtil.ROWSTARTINDEX_KEY, 0);
        }
        if (!paramMap.containsKey(PageUtil.ROWENDINDEX_KEY)) {
            paramMap.put(PageUtil.ROWENDINDEX_KEY, 1);
        }
        List<T> list = this.getModelList(paramMap);
        return list.size() >= 1 ? list.get(0) : null;
    }

    @Override
    public DbType dbType() {
        return DbType.MYSQL;
    }

    @Override
    public List<T> getModelList1(Map<String, Object> map, int skip, int rows) throws Exception {
        return this.getModelList(null, map, skip, rows);
    }

    protected List<T> getModelList(String sqlMapId, Map<String, Object> map, int skip, int rows) throws Exception {
        map = PageUtil.disposeParamMap(map, this.dbType(), skip, rows);
        return this.getModelList(sqlMapId, map);
    }

    @Override
    public PageModel<T> getPageModel(Map map, int page, int rows) throws Exception {
        return this.getPageModel(null, map, page, rows);
    }

    protected <O> PageModel<O> getPageModel(String sqlMapId, Map map, int page, int rows)
            throws Exception {
        if (map == null) {
            map = FrameUtil.newHashMap();
        }
        if (map != null) {
            Object obj = map.get("order");
            if (obj != null && map.get("sort") != null) {
                FrameUtil.throwBaseException("请问你想干嘛?");
            }
            if (obj != null) {
                String order = obj.toString().trim().toUpperCase();
                if (!order.startsWith("ORDER")) {
                    FrameUtil.throwBaseException("请问你想干嘛?");
                }
            }
        }
        map.put(PageUtil.PAGE_KEY, page);
        map.put(PageUtil.ROWS_KEY, rows);
        return PageUtil.getPageModel(new IPage() {

            @Override
            public List getPageList(Map<String, Object> paramMap, String sqlMapId) throws Exception {
                return BaseDaoImpl.this.getModelList(sqlMapId, paramMap);
            }

            @Override
            public long getPageCount(Map<String, Object> map, String sqlMapId) throws Exception {
                return BaseDaoImpl.this.getModelListCount(sqlMapId, map);
            }
        }, map, sqlMapId, this.dbType());
    }

    /**
     * 主键名称
     *
     * @return
     */
    protected abstract String getPrimaryKeyName();

    protected abstract IBaseMapper<T> getBaseMapper();
}
